#include "user_timer.h"
//#include "myRTC.h"
#include "relay_output.h"
#include "myRTC.h"
#include "iotgo_service.h"
#include "platformAPI.h"

#include <time.h>


#define DEBUG_TASK_TIEMR 1

#ifdef DEBUG_TASK_TIMER
#include <stdio.h>
#endif

#define tskTimer_PRIORITY (tskIDLE_PRIORITY + 2)
#define MAX_TIMER_NUM 8
#define MAX_RECORD_TIMER_NUM 8

static xTaskHandle timerTsk;

#define TIMER_TYPE_NONE   0
#define TIMER_TYPE_ONCE   1
#define TIMER_TYPE_REPEAT 2

struct timer_head
{
    int8_t type;
    int8_t is_triggered;
    int8_t switch_state;
};

struct timer_once
{
    struct timer_head head;
    int32_t t_year;
    int8_t t_mon;
    int8_t t_mday;
    int8_t t_hour;
    int8_t t_min;
};

struct timer_repeat
{
    struct timer_head head;
    int8_t t_hour;
    int8_t t_min;
    int8_t wday[7];
};

typedef union
{
    struct timer_head head;
    struct timer_once once;
    struct timer_repeat repeat;
} UserTimer;

static UserTimer timer_list[MAX_RECORD_TIMER_NUM];

static int8_t getWeek(int32_t y, int8_t m, int8_t d)
{
    int8_t c;
    int32_t w;
    
    if (m < 3) 
    {
        y -= 1;
        m += 12;
    }
    c = y/100;
    y %= 100;
    
    w = y + y/4 + c/4 - 2*c + ((26*(m+1))/10 + d - 1);
    w = ( w % 7 + 7 ) % 7;
    return (int8_t)w;
}

static void parseTimeMessage(UserTimer *p_timer, uint8_t *date, uint8_t *type)
{
    uint8_t s_year[5] = {0};
    uint8_t s_mon[3] = {0};
    uint8_t s_day[3] = {0};
    uint8_t s_hour[3] = {0};
    uint8_t s_minute[3] = {0};

    int8_t count = 0;
    int8_t wday_tmp = 0;
    int8_t *str_tmp = NULL;
    
    if(strcmp(type,"once") == 0)
    {
        /*date should be like: "2016-03029T06:56:08.514Z"*/ 
        if(*(date + 4)  == '-' &&
           *(date + 7)  == '-' &&
           *(date + 10) == 'T' &&
           *(date + 13) == ':' &&
           *(date + 16) == ':' &&
           *(date + 19) == '.' &&
           *(date + 23) == 'Z')  
        {
            /*right date format*/
            memcpy(s_year,date,4);
            memcpy(s_mon,date+5,2);
            memcpy(s_day,date+8,2);
            memcpy(s_hour,date+11,2);
            memcpy(s_minute,date+14,2);
            printf("timer is %s\n",date);
            printf("t_year is %d\n",p_timer->once.t_year);
            p_timer->once.t_year = atoi(s_year);
            p_timer->once.t_mon = atoi(s_mon);
            p_timer->once.t_mday = atoi(s_day);
            p_timer->once.t_hour = atoi(s_hour);
            p_timer->once.t_min = atoi(s_minute);
            p_timer->once.head.type = TIMER_TYPE_ONCE;
            p_timer->once.head.is_triggered = 0;
        } 
    }
    else if(strcmp(type,"repeat") == 0)
    {
        str_tmp = strtok(date," ,");
        while(str_tmp != NULL)
        {
            printf("[parse repeat date]: %s\n",str_tmp);
            switch(count)
            {
            case 0:
                p_timer->repeat.t_min = atoi(str_tmp);
                break;
            case 1:
                p_timer->repeat.t_hour = atoi(str_tmp);
                break;
            case 2:
            case 3:
                break;
            default:
                wday_tmp = atoi(str_tmp);
                p_timer->repeat.wday[wday_tmp] = 1;
                break;
            }
            str_tmp = strtok(NULL," ,");
            count++;
        }
        p_timer->repeat.head.type = TIMER_TYPE_REPEAT;
        p_timer->repeat.head.is_triggered = 0;
    }
    else
    {
        p_timer->head.type = TIMER_TYPE_NONE;
        p_timer->head.is_triggered = 1;
    }
}

void updateTimerList(uint8_t *sequence, int8_t *params)
{
    cJSON *cjson_params = NULL;
    cJSON *cjson_timer_array = NULL;
    cJSON *cjson_array[MAX_TIMER_NUM];
    cJSON *cjson_at_time[MAX_TIMER_NUM];
    cJSON *cjson_timer_type[MAX_TIMER_NUM];
    cJSON *cjson_timer_action[MAX_TIMER_NUM];
    cJSON *cjson_switch_state[MAX_TIMER_NUM];
    struct tm switch_time[MAX_TIMER_NUM];
    int8_t earlist_record_nums[MAX_RECORD_TIMER_NUM];
    int8_t array_num = 0;
    int8_t count = 0;

    for(count = 0; count < MAX_TIMER_NUM; count++)
    {
        cjson_array[count] = NULL;
        cjson_at_time[count] = NULL;
        cjson_timer_type[count] = NULL;
        cjson_timer_action[count] = NULL;
        cjson_switch_state[count] = NULL;
    }
   
    cjson_params = cJSON_Parse(params);
    if(cjson_params)
    {
        cjson_timer_array = cJSON_GetObjectItem(cjson_params,"timers");
        if(cjson_timer_array)
        {
            array_num = cJSON_GetArraySize(cjson_timer_array);
            printf("relay num is %d\n",array_num);
            iotgoWriteErrorNumToServer(0,sequence);
            /* parse each timer set*/
            for(count = 0; count < array_num; count++)
            {
                cjson_array[count] = cJSON_GetArrayItem(cjson_timer_array,count);
                if(cjson_array[count])
                {
                    cjson_timer_type[count] = cJSON_GetObjectItem(cjson_array[count],"type");
                    cjson_at_time[count] = cJSON_GetObjectItem(cjson_array[count],"at");
                    cjson_timer_action[count] = cJSON_GetObjectItem(cjson_array[count],"do");
                    if(cjson_timer_action[count])
                    {
                        cjson_switch_state[count] = cJSON_GetObjectItem(cjson_timer_action[count],"switch");
                    }
                    
                    if(cjson_timer_type[count] && 
                       cjson_at_time[count] && 
                       cjson_switch_state[count])
                    {
                        printf("timer[%d]; type is [%s];at [%s]; action [%s]\n",
                                count,
                                cjson_timer_type[count]->valuestring,
                                cjson_at_time[count]->valuestring,
                                     cjson_switch_state[count]->valuestring);
                        parseTimeMessage(&timer_list[count],
                                         cjson_at_time[count]->valuestring,
                                         cjson_timer_type[count]->valuestring);
                        
                        if(strcmp(cjson_switch_state[count]->valuestring,"on") == 0)
                        {
                            timer_list[count].head.switch_state = RELAY_ON;
                        }
                        else
                        {
                            timer_list[count].head.switch_state = RELAY_OFF;
                        }
                    }/* cjson_type[count] && cjson_at_time[count] && cjson_outlet[count] && cjson_switch_state[count] */
                }/* cjson_array[count] */
            }/* for(count = 0; count < 4; count++)*/
        }/*cjson_relay_array*/
        cJSON_Delete(cjson_params);
        iotgoWriteErrorNumToServer(0,sequence);
    }
}


static void do_the_action(struct timer_head * p_timer_head)
{
    if(p_timer_head->switch_state == RELAY_ON)
    {
        turnOnRelay();
    }
    else if(p_timer_head->switch_state == RELAY_OFF)
    {
        turnOffRelay();
    }
}


static void checkTheUserTimers(void)
{
    struct tm *p_time;
    uint8_t count = 0;
    time_t seconds;

    /*step1: get current time*/
    seconds = myRTCread();
    
    //printf("seconds is %ld\n",seconds);
    p_time = gmtime(&seconds);
    p_time->tm_year += 1970;
    p_time->tm_wday = getWeek(p_time->tm_year,p_time->tm_mon,p_time->tm_mday);
#if 1
    printf("gmtime: %d-%d-%d [%d] %d:%d:%d\n",
            p_time->tm_year,
            p_time->tm_mon,
            p_time->tm_mday,
            p_time->tm_wday,
            p_time->tm_hour,
            p_time->tm_min,
            p_time->tm_sec);
#endif
    /*step2: compare with user's set*/
    for(count = 0; count < MAX_RECORD_TIMER_NUM; count++)
    {
        //printf("check timer[%d]\n",count);
        /*step2.1 check timer type */
        if(timer_list[count].head.type == TIMER_TYPE_ONCE &&
           timer_list[count].head.is_triggered == 0)
        {
            printf("this is once timer\n");
            printf("timer_list[count].once.t_year [%d] || tm_year [%d]\n", 
                   timer_list[count].once.t_year,p_time->tm_year);
            printf("timer_list[count].once.t_mon [%d] || tm_mon [%d]\n", 
                   timer_list[count].once.t_mon,p_time->tm_mon);
            printf("timer_list[count].once.t_mday [%d] || tm_mday [%d]\n", 
                   timer_list[count].once.t_mday,p_time->tm_mday);
            printf("timer_list[count].once.t_hour [%d] || tm_hour [%d]\n", 
                   timer_list[count].once.t_hour,p_time->tm_hour);
            printf("timer_list[count].once.t_min [%d] || tm_min [%d]\n", 
                   timer_list[count].once.t_min,p_time->tm_min);
            /*step2.1 check time*/
            if(timer_list[count].once.t_year == p_time->tm_year &&
               timer_list[count].once.t_mon  == p_time->tm_mon  &&
               timer_list[count].once.t_mday == p_time->tm_mday &&
               timer_list[count].once.t_hour == p_time->tm_hour &&
               timer_list[count].once.t_min  == p_time->tm_min)
            {
                printf("got time\n");
                do_the_action(&timer_list[count].once.head);
                timer_list[count].once.head.is_triggered = 1;
            }//check time
        }
        else if(timer_list[count].head.type == TIMER_TYPE_REPEAT &&
                timer_list[count].head.is_triggered == 0)
        {
            printf("this repeat timer\n");
            if(timer_list[count].repeat.t_hour == p_time->tm_hour &&
               timer_list[count].repeat.t_min  == p_time->tm_min &&
               timer_list[count].repeat.wday[p_time->tm_wday] == 1)
            {
                printf("got time\n");
                do_the_action(&timer_list[count].repeat.head);
                timer_list[count].once.head.is_triggered = 0;
            }
        }
    }
}

static void userTimerThread(void *parameter)
{
    int32_t iotgo_state = IOTGO_IDLE;
    uint8_t second_count = 0;
    uint8_t timer_query_params[]="[\"timers\"]";

    //softRTCinit();
    /*wait for wormhole ready*/
    while(1)
    {
        systemDelayMs(1000);
        iotgo_state = iotgoGetState();
        if(iotgo_state == IOTGO_REGISTER_IS_READY)
        {
            printf("[userTimerThread] send date query\n");
            iotgoWriteDateQueryToServer();
            iotgoWriteQueryToServer(timer_query_params);
            break;
        }     
    }

    while(1)
    {
        second_count++;
        /*check the user_timers every second*/
        checkTheUserTimers();

        /*send date query every minite*/
        if(second_count == 60)
        {
            second_count = 0;
            iotgoWriteDateQueryToServer();
        }

        /*send user_timers query every minite*/
        if(second_count == 30)
        {
            ;
        }

        systemDelayMs(1000);
    }
}

int startUserTimerTask(void)
{
    if(xTaskCreate(userTimerThread, 
		   ((const char*)"userTimerThread"), 
		   1000, 
		   NULL,
		   tskTimer_PRIORITY,
		   &timerTsk) != pdPASS)
    {	
        printf("create connect_servers_threads failed\n");
	return -1;
    }
    return 0;
}


int stopUserTimeTask(void)
{
    //myRTCstop();
    if(isSoftRTCenable() == 1)
    {
        softRTCfree();
    }
    vTaskDelete(timerTsk);
    return 0;
}

